#ifndef BLISP_ENV_H
#define BLISP_ENV_H

/* In powers of 2, so size of n is actually 2^n */
#define ENV_STK_SIZE 5 /* actual size of 32 */
#define pow2(n) (1 << (n))

#define Env_newinit() Env_init(Env_new())
#define Env_push(env) ++Env_tos
#define Env_pop(env) Env_tos--
#define Env_tos(env) (env)->data_stack_top
#define Env_cpush(env) ++Env_ctos(env)
#define Env_cpop(env) Env_ctos(env)--
#define Env_ctos(env) (env)->call_stack_top
#define Env_ctos_set_pos(env,npos) Env_ctos(env)->pos = (npos)
#define Env_ctos_set_fp(env,fp) Env_ctos(env)->func_base = (fp)
#define Env_set_blk_open(env) Env_ctos(env)->block_info |= block_open
#define Env_set_blk_init(env) Env_ctos(env)->block_info |= block_init
#define Env_get_blk_open(env) Env_ctos(env)->block_info & block_open
#define Env_get_blk_init(env) Env_ctos(env)->block_info & block_init

#define block_open 1
#define block_init 2

typedef Object *StkPos;
typedef struct callStkPos CallStkPos;
typedef struct blisp_env blisp_Env;

struct callStkPos
{
	StkPos pos;
	StkPos func_base;
	int block_info;
};

struct blisp_env
{
	Pair *syntax_tree;
	Symbol *globals;

	/* Keep track of location in syntax tree */
	CallStkPos *call_stack; /* base / lowest slot */
	CallStkPos *call_stack_top;
	size_t call_stack_size;

	/* Standard data manipulation stack */
	StkPos *data_stack; /* base / lowest slot */
	StkPos *data_stack_top; /* ASM "SP" */
	size_t data_stack_size;

	Function *current_func;
	StkPos func_base; /* ASM "FP" or "BP" */
};

blisp_Env *Env_new(void); /* presently, just prototype */
#define Env_new() GC_NEW(blisp_Env)
blisp_Env *Env_init(blisp_Env *);
void Env_pushBlock(blisp_Env *);
void Env_closeBlock(blisp_Env *);

#endif /* !BLISP_ENV_H */
